﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using MvdDonk.Bomberman.Entities;
using MvdDonk.Bomberman.Network.Messages;
using Microsoft.Xna.Framework.Graphics;
using TiledLib;

namespace MvdDonk.Bomberman.Managers
{
    class EntityManager
    {
        public List<Player> Players { get; private set; }
        public List<Entity> Entities { get; private set; }

        private Player _LocalPlayer;
        public Player LocalPlayer
        {
            get
            {
                if (_LocalPlayer == null)
                    _LocalPlayer = Players.FirstOrDefault(p => p.IsLocalPlayer);
                return _LocalPlayer;
            }
        }

        private Vector2 previousMovementVector;
        private double positionSyncTimer;
        private double positionSyncInterval = 250;

        public void Initialize()
        {
            Players = new List<Player>();
            Entities = new List<Entity>();
        }

        public void Update(GameTime gameTime, Map map)
        {
            Entities.ForEach(p => p.Update(gameTime, map));
            Players.ForEach(p => p.Update(gameTime, map));

            if (LocalPlayer != null)
            {
                if (LocalPlayer.MovementVector != previousMovementVector)
                    Bomberman.Instance.NetworkManager.Client.UpdateMovement(LocalPlayer.MovementState, LocalPlayer.MovementVector);

                positionSyncTimer += gameTime.ElapsedGameTime.TotalMilliseconds;
                if (positionSyncTimer >= positionSyncInterval)
                {
                    positionSyncTimer = 0;
                    Bomberman.Instance.NetworkManager.Client.SyncPosition(LocalPlayer.Position);
                }

                previousMovementVector = LocalPlayer.MovementVector;
            }
        }

        public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
        {
            Entities.ForEach(p => p.Draw(spriteBatch));
            Players.ForEach(p => p.Draw(spriteBatch));
        }

        public void AddPlayer(Player player)
        {
            Players.Add(player);
        }

        public void AddEntity(Entity entity)
        {
            if (entity is Player)
                throw new Exception("Do not add players with this method, use AddPlayer instead");

            Entities.Add(entity);
        }

        public void RemoveEntity(Entity entity)
        {
            if (Entities.Contains(entity))
                Entities.Remove(entity);
        }

        public void DisconnectPlayer(long networkId)
        {
            //TODO make more fancy, set state on player and blink him or something?
            Players.RemoveAll(p => p.NetworkId == networkId);
        }

        public void PlayerMovementUpdate(MovementMessage message)
        {
            var player = Players.FirstOrDefault(p => p.NetworkId == message.NetworkId);
            if (player != null)
            {
                player.MovementState = message.MovementState;
                player.MovementVector = message.MovementVector;
            }
        }

        public void PlayerPositionUpdate(PositionMessage message)
        {
            var player = Players.FirstOrDefault(p => p.NetworkId == message.NetworkId);
            if (player != null)
            {
                player.Position = message.Position;
            }
        }


        ////temporary
        //private float time;

        //public float Time
        //{
        //    get { return time; }
        //    set { time = value; }
        //}

        //private QuadTree quadTree;

        //private List<GraphicalEntity> results;

        //internal List<GraphicalEntity> Results
        //{
        //    get { return results; }
        //    set { results = value; }
        //}

        //internal QuadTree QuadTree
        //{
        //    get { return quadTree; }
        //    set { quadTree = value; }
        //}

        //public EntityManager()
        //{
        //    float gridSize = 262144.0f / 2;
        //    quadTree = new QuadTree(new Vector2(-gridSize / 2, -gridSize / 2), gridSize, null, QuadType.Parent);
        //    Random r = AwesomeZombie.Instance.Random;
        //    Time = 1.0f;
        //    selectRect = new Rectangle(400, 400, 400, 400);
        //    results = new List<GraphicalEntity>();
        //}

        //public Hashtable Entities
        //{
        //    get { return entities; }
        //    set { entities = value; }
        //}

        //public void AddEntity(Entity entity)
        //{
        //    //Events
        //    entity.entitiesInLine += new Entity.onEntitiesInLine(EntitiesInLine);
        //    entity.entitiesInRadius += new Entity.onEntitiesInRadius(EntitiesInRadius);
        //    entity.fetchAll += new Entity.onFetchAll(FetchAll);
        //    entity.createEntity += new Entity.onCreate(AddEntity);

        //    newEntities.Add(entity.Id, entity);

        //    if (entity is GraphicalEntity)
        //        quadTree.Insert((GraphicalEntity)entity);

        //    entity.Initialize();
        //}

        //public void Think(GameTime gameTime)
        //{
        //    results.Clear();
        //    quadTree.Select(selectRect, ref results);

        //    foreach (GraphicalEntity g in results)
        //    {
        //        g.Think(gameTime);
        //    }
        //}

        //public void CollideAndMove()
        //{
        //    List<PhysicalEntity> temp = new List<PhysicalEntity>();

        //    foreach (GraphicalEntity g in results)
        //    {
        //        if (g is PhysicalEntity)
        //            temp.Add((PhysicalEntity)g);
        //    }

        //    for (int i = 0; i < temp.Count; i++)
        //    {
        //        ((PhysicalEntityState)temp[i].CurrentState).CollideAndMove(temp);
        //    }
        //}

        ///*
        //public void CollideAndMove()
        //{
        //    List<GraphicalEntity> temp = new List<GraphicalEntity>();
        //    List<PhysicalEntity> toCheck = new List<PhysicalEntity>();
        //    Rectangle rect = new Rectangle();

        //    foreach (GraphicalEntity g in results)
        //    {
        //        if (g is PhysicalEntity)
        //        {
        //            rect.X = (int)(g.CenterPosition.X - 150.0f);
        //            rect.Y = (int)(g.CenterPosition.Y - 150.0f);
        //            rect.Width = 300;
        //            rect.Height = 300;

        //            temp.Clear();
        //            toCheck.Clear();

        //            quadTree.Select(rect, ref temp);

        //            foreach (GraphicalEntity g2 in temp)
        //                if (g2 is PhysicalEntity)
        //                    toCheck.Add((PhysicalEntity)g2);

        //            ((PhysicalEntityState)g.CurrentState).CollideAndMove(toCheck);
        //        }
        //    }
        //}
        //*/

        //public void AddListOfEntities(List<Entity> list)
        //{
        //    foreach (Entity e in list)
        //    {
        //        this.AddEntity(e);
        //    }
        //}

        //public void AddListOfEntities(List<GraphicalEntity> list)
        //{
        //    foreach (GraphicalEntity e in list)
        //    {
        //        this.AddEntity(e);
        //    }
        //}

        //public void UpdateTreePositions()
        //{
        //    foreach (GraphicalEntity g in results)
        //        g.UpdateTreePosition();
        //}

        //public Entity GetEntity(Object id)
        //{
        //    return (Entity)entities[id];
        //}

        //public void AddEntities()
        //{
        //    foreach (DictionaryEntry entry in newEntities)
        //    {
        //        entities.Add(entry.Key, entry.Value);
        //    }

        //    newEntities.Clear();
        //}

        //public void RemoveEntities()
        //{
        //    object[] keys = new object[entities.Count];
        //    entities.Keys.CopyTo(keys, 0);

        //    for (int index = keys.Length - 1; index >= 0; --index)
        //    {
        //        if (!((Entity)entities[keys[index]]).Alive)
        //            entities.Remove(keys[index]);
        //    }

        //    // Quadtree
        //    /*
        //    foreach (GraphicalEntity g in results)
        //    {
        //        if (g.Alive == false)
        //            g.QuadTree.Remove(g);
        //    }
        //     */
        //}

        //public void EntitiesInLine(Line line, ArrayList result)
        //{
        //    ArrayList l = new ArrayList();

        //    foreach (GraphicalEntity g in results)
        //    {
        //        if (Line.IsCut(new Line(g.Position, g.Position + g.Bounds), line) ||
        //            Line.IsCut(new Line(new Vector2(g.Position.X, g.Position.Y + g.Bounds.Y), new Vector2(g.Position.X + g.Bounds.X, g.Position.Y)), line))
        //        {
        //            l.Add(g);
        //        }
        //    }

        //    result.AddRange(l);
        //}

        //public void EntitiesInRadius(float radius, Vector2 position, ArrayList result)
        //{
        //    ArrayList l = new ArrayList();

        //    foreach (GraphicalEntity g in results)
        //    {
        //        if ((g.Position + g.Bounds / 2 - position).Length() <= radius)
        //            l.Add(g);
        //    }

        //    result.AddRange(l);
        //}

        //public ArrayList EntitiesInBox(PhysicalEntity box)
        //{
        //    ArrayList l = new ArrayList();

        //    foreach (GraphicalEntity g in results)
        //    {
        //        if (PhysicalEntity.RectangularIntersects(g, box))
        //            l.Add(g);
        //    }

        //    return l;
        //}


        //public void FetchAll(Type type, ArrayList result)
        //{
        //    ArrayList list = new ArrayList();

        //    foreach (GraphicalEntity g in results)
        //    {
        //        if (g.GetType().Equals(type))
        //            list.Add(g);
        //    }

        //    result.AddRange(list);
        //}

        //public void RemoveAll(Type type)
        //{
        //    object[] keys = new object[this.Entities.Count];
        //    this.Entities.Keys.CopyTo(keys, 0);

        //    for (int index = keys.Length - 1; index >= 0; --index)
        //    {
        //        if (entities[keys[index]].GetType().Equals(type))
        //            entities.Remove(keys[index]);
        //    }
        //}
    }
}
